package com.luoqiwen.minecraft.plugin.interactblocker;

import org.bukkit.ChatColor;
import org.bukkit.Material;
import org.bukkit.configuration.InvalidConfigurationException;
import org.bukkit.configuration.file.YamlConfiguration;
import org.bukkit.event.EventHandler;
import org.bukkit.event.HandlerList;
import org.bukkit.event.Listener;
import org.bukkit.event.block.Action;
import org.bukkit.event.player.PlayerInteractEvent;
import org.bukkit.plugin.java.JavaPlugin;

import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Locale;

public final class InteractBlocker extends JavaPlugin
{
    private static final String Bypass = "interactblocker.bypass";
    private static final String BypassBlock = Bypass + ".block.";
    private static final String BypassHold = Bypass + ".hold.";

    private final File confFile = new File(getDataFolder(), "config.yml");
    private final YamlConfiguration config = new YamlConfiguration();

    @Override
    public void onEnable()
    {
        // Plugin startup logic
        info("Loading plugin...");

        loadConf();

        getServer().getPluginManager().registerEvents(new Listener()
        {
            @EventHandler(ignoreCancelled = true)
            public void onInteract(PlayerInteractEvent e)
            {
                runAsync(()->
                {
                    checkBlock(e);

                    checkHolding(e);
                });
            }

            private void checkBlock(PlayerInteractEvent e)
            {
                if (e.getClickedBlock() == null || e.getClickedBlock().getType().equals(Material.AIR))
                    return;

                String BlockName = e.getClickedBlock().getType().name();
                String BlockPerm = BypassBlock + BlockName;

                if (e.getAction().equals(Action.RIGHT_CLICK_BLOCK)
                        && (!e.getPlayer().hasPermission(Bypass))
                        && (!e.getPlayer().hasPermission(BlockPerm))
                        //simple math:
                        && (config.getBoolean("Blocks_blacklist") == config.getStringList("Blocks").contains(BlockName)))
                {
                    debug("Blocked interact at: " + e.getPlayer().getLocation() );
                    e.setCancelled(true);
                    e.getPlayer().sendMessage(BlockDeny(BlockName));
                }
            }

            private void checkHolding(PlayerInteractEvent e)
            {
                String MainHold = e.getPlayer().getInventory().getItemInMainHand().getType().name();
                String OffHold = e.getPlayer().getInventory().getItemInOffHand().getType().name();
                String MainHoldPerm = BypassHold + MainHold;
                String OffHoldPerm = BypassHold + OffHold;

                if (e.getAction().equals(Action.RIGHT_CLICK_BLOCK)
                        && (!e.getPlayer().hasPermission(Bypass))
                        && (!e.getPlayer().hasPermission(MainHoldPerm))
                        && (!e.getPlayer().hasPermission(OffHoldPerm)))
                {
                    if (config.getBoolean("Holdings_blacklist") == config.getStringList("Holdings").contains(MainHold))
                    {
                        e.getPlayer().sendMessage(HoldingDeny(MainHold));
                        debug("Blocked interact at: " + e.getPlayer().getLocation() );
                        e.setCancelled(true);
                    }
                    else if (config.getBoolean("Holdings_blacklist") == config.getStringList("Holdings").contains(OffHold))
                    {
                        e.getPlayer().sendMessage(HoldingDeny(OffHold));
                        debug("Blocked interact at: " + e.getPlayer().getLocation() );
                        e.setCancelled(true);
                    }
                }
            }

        }, this);

        getCommand("interactblocker").setExecutor((commandSender, command, s, strings) ->
        {
            if (commandSender.hasPermission("interactblocker.use"))
            {
                if (commandSender.hasPermission("interactblocker.reload") && strings.length == 1 && strings[0].equalsIgnoreCase("reload"))
                {
                    loadConf();
                    commandSender.sendMessage(translateColor(config.getString("reloadedMsg")));
                }
                else
                {
                    commandSender.sendMessage(translateColor(config.getString("helpMsg")));
                }

                return true;
            } else
                return false;
        });

        getCommand("interactblocker").setTabCompleter((commandSender, command, s, strings) -> List.of("reload"));
    }

    @Override
    public void onDisable()
    {
        // Plugin shutdown logic
        info("Unloading plugin...");
        HandlerList.unregisterAll(this);
        getServer().getScheduler().cancelTasks(this);
    }

    private void loadConf()
    {
        if (!confFile.exists())
            saveResource("config.yml", true);

        try
        {
            config.load(confFile);
        }
        catch (IOException | InvalidConfigurationException e)
        {
            e.printStackTrace();
            warn("Failed to load resource");
            getPluginLoader().disablePlugin(this);
        }

        runAsync(()->
        {
            //fix config
            ArrayList<String> BlockList = new ArrayList<>();
            ArrayList<String> HoldingList = new ArrayList<>();

            config.getStringList("Blocks").forEach(s ->
            {
                String upper = s.toUpperCase(Locale.ENGLISH);

                if (!s.equals(upper))
                    info("Fixed config: " + s + " -> " + upper);

                BlockList.add(upper);
            });

            config.getStringList("Holdings").forEach(s ->
            {
                String upper = s.toUpperCase(Locale.ENGLISH);

                if (!s.equals(upper))
                    info("Fixed config: " + s + " -> " + upper);

                HoldingList.add(upper);
            });

            config.set("Blocks", BlockList);
            config.set("Holdings", HoldingList);

            try
            {
                config.save(confFile);
            }

            catch (IOException e)
            {
                e.printStackTrace();
                warn("Failed to save fixed config");
            }

            StringBuilder builder = new StringBuilder();

            builder.append("Blacklisted blocks:\n&a");
            config.getStringList("Blocks").forEach(s ->
                    builder.append(s).append(" "));

            builder.append("\n&bBlacklisted holdings:\n&a");
            config.getStringList("Holdings").forEach(s ->
                    builder.append(s).append(" "));

            info(builder.toString());
        });
    }

    private void info(Object msg)
    {
        getLogger().info(ChatColor.AQUA + translateColor(msg));
    }

    private void warn(Object msg)
    {
        getLogger().warning(ChatColor.DARK_RED + translateColor(msg));
    }

    private void debug(Object msg)
    {
        if (config.getBoolean("debug"))
            getLogger().info(ChatColor.GOLD + translateColor(msg));
    }

    private void runAsync(Runnable run)
    {
        getServer().getScheduler().runTaskAsynchronously(this, run);
    }

    private String BlockDeny(String material)
    {
        String orig = getConfig().getString("blockedMsg_block");
        if (orig == null)
            return "";

        orig = orig.replaceAll("%0%", material);
        return ChatColor.translateAlternateColorCodes('&', orig);
    }

    private String HoldingDeny(String material)
    {
        String orig = getConfig().getString("blockedMsg_item");
        if (orig == null)
            return "";

        orig = orig.replaceAll("%0%", material);
        return ChatColor.translateAlternateColorCodes('&', orig);
    }

    private String translateColor(Object msg)
    {
        return msg == null ? "" : ChatColor.translateAlternateColorCodes('&', msg.toString());
    }


}
